// https://github.com/wechat-miniprogram/minigame-canvas-engine/blob/master/src/components/elements.ts
function delayTime(time) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(time)
    }, time)
  })
}
function promiseDraw(content, reserve) {
  return new Promise(resolve => {
    content.draw(reserve, resolve)
  })
}
class Util {
  /**
   * type1: 0, 25, 17, rgba(0, 0, 0, 0.3)
   * type2: rgba(0, 0, 0, 0.3) 0px 25px 17px 0px => (0, 25, 17, rgba(0, 0, 0, 0.3))
   * @param {*} shadow
   */
  static transferBoxShadow(shadow = '', type) {
    if (!shadow || shadow === 'none') return
    let color
    let split

    split = shadow.match(/(\w+)\s(\w+)\s(\w+)\s(rgb.*)/)

    if (split) {
      split.shift()
      shadow = split
      color = split[3] || '#ffffff'
    }
    else {
      split = shadow.split(') ')
      color = `${split[0]})`
      shadow = split[1].split('px ')
    }

    return {
      offsetX: +shadow[0] || 0,
      offsetY: +shadow[1] || 0,
      blur: +shadow[2] || 0,
      color
    }
  }

  static isColor(bgVal) {
    let type = ''
    if (/^rgb\(/.test(bgVal)) {
      // 如果是rgb开头，200-249，250-255，0-199
      type
        = '^[rR][gG][Bb][\(]([\\s]*(2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?)[\\s]*,){2}[\\s]*(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)[\\s]*[\)]{1}$'
    }
    else if (/^rgba\(/.test(bgVal)) {
      // 如果是rgba开头，判断0-255:200-249，250-255，0-199 判断0-1：0 1 1.0 0.0-0.9
      type
        = '^[rR][gG][Bb][Aa][\(]([\\s]*(2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?)[\\s]*,){3}[\\s]*(1|1.0|0|0.[0-9])[\\s]*[\)]{1}$'
    }
    else if (bgVal.startsWith('#')) {
      // 六位或者三位
      type = '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$'
    }
    else if (/^hsl\(/.test(bgVal)) {
      // 判断0-360 判断0-100%(0可以没有百分号)
      type
        = '^[hH][Ss][Ll][\(]([\\s]*(2[0-9][0-9]|360｜3[0-5][0-9]|[01]?[0-9][0-9]?)[\\s]*,)([\\s]*((100|[0-9][0-9]?)%|0)[\\s]*,)([\\s]*((100|[0-9][0-9]?)%|0)[\\s]*)[\)]$'
    }
    else if (/^hsla\(/.test(bgVal)) {
      type
        = '^[hH][Ss][Ll][Aa][\(]([\\s]*(2[0-9][0-9]|360｜3[0-5][0-9]|[01]?[0-9][0-9]?)[\\s]*,)([\\s]*((100|[0-9][0-9]?)%|0)[\\s]*,){2}([\\s]*(1|1.0|0|0.[0-9])[\\s]*)[\)]$'
    }
    const re = new RegExp(type)
    return !!bgVal.match(re)
  }

  /* 渐变 */
  normalizeLinearGradient(str) {
    const match = str.match(/linear-gradient\((.*)\)/) // match(/linear-gradient\((["'])(.*?)\1\)/)
    return match && match[1]
  }

  /* 颜色 */
  normalizeColor(str) {
    const match = str.match(/rgba?\((\d{1,3}), (\d{1,3}), (\d{1,3})(, \d(\.\d+)?)?\)/)
    return match && match[0]
  }

  /* 边框 */
  normalizeBorder(str) {
    const match = str.match(/(.*)(solid|none|dashed|dotted)(.*)/)
    if (!match) return [0, '', '']
    return match && [Number.parseFloat(match[1]), match[2], match[3].replace(/\s/g, '')]
  }

  /* 解析图片 */
  static parseImgBg(str) {
    const match = str.match(/url\((["'])(.*?)\1\)/)
    return match && match[2]
  }

  /* 解析渐变 */
  static parseLinearGradient(str) {
    const match = str.match(/linear-gradient\((.*)\)/) // match(/linear-gradient\((["'])(.*?)\1\)/)

    const getColor = (str) => str.match(
      /rgba?\((\d{1,3}), (\d{1,3}), (\d{1,3})(, \d(\.\d+)?)?\)/g
    ) || []

    const direction = (str) => {
      const d = str.match(/\s*([^,]*)/)
      return d && d[0]
    }
    const linear = match && match[1]
    if (linear) {
      const dir = direction(linear)
      const colors = getColor(linear)
      return {
        dir,
        colors
      }
    }
    return null
  }

  /* 解析颜色 */
  static parseBgColor(str) {
    const match = str.match(/rgba?\((\d{1,3}), (\d{1,3}), (\d{1,3})(, \d(\.\d+)?)?\)/)
    return match && match[0]
  }

  /* 解析边框 */
  static parseBorder(style, scale) {
    const borders = [];
    ['border-top', 'border-right', 'border-bottom', 'border-left'].forEach(e => {
      const borderSty = style[e]
      if (!borderSty) return
      const match = borderSty.match(/(.*)(solid|none|dashed|dotted)(.*)/)
      if (!match) return
      borders.push({
        width: Number.parseFloat(match[1] || 0) * scale,
        style: match[2],
        color: match[3].replace(/\s/g, '')
      })
    })
    return borders
  }

  static parseBorderRadius(borderRadius, scale) {
    const radius = borderRadius.split(' ').map(e => Number.parseFloat(e))
    if (radius.length === 1) {
      return [radius * scale, radius * scale, radius * scale, radius * scale]
    }
    const [topLeft = 0, topRight = 0, rightBottom = 0, leftBottom = 0] = radius
    return [topLeft * scale, topRight * scale, rightBottom * scale, leftBottom * scale]
  }
}
class Layout {
  constructor(vm, renderClassName, baseWidth = 750) {
    this.$vm = vm
    this.renderClassName = renderClassName
    this.baseWidth = baseWidth // 基准宽度，默认取 iOS 750
  }

  /* 图片 */
  normalizeImgBg(str) {
    const match = str.match(/url\((["'])(.*?)\1\)/)
    return match && match[2]
  }

  getElementTree(cb) {
    const query = uni.createSelectorQuery().in(this.$vm)
    query.selectAll(`.${this.renderClassName}`).fields({
      id: true,
      dataset: true,
      rect: true,
      size: true,
      context: true,
      computedStyle: ['background', 'color', 'z-index', 'line-height', 'font-size', 'font-family', 'font-weight', 'text-decoration', 'text-align', 'text-indent', 'border', 'border-radius', 'border-top', 'border-left', 'border-right', 'border-bottom', 'padding', 'letter-spacing']
    }, data => {
      if (!data || data.length === 0) {
        console.log('未获取到dom节点')
        return
      }
      try {
        const renderList = this.createTree(data)
        cb && cb(renderList)
      }
      catch (e) {
        console.log(e)
      }
    }).exec()
  }

  createTree(renderData) {
    let scale = 1

    const renderList = []
    let root = null
    let rootTop = 0
    let rootLeft = 0

    for (let i = 0; i < renderData.length; i++) {
      const item = renderData[i]
      if (i === 0) {
        scale = Math.abs(this.baseWidth / item.width)

        rootTop = item.top * scale
        rootLeft = item.left * scale
      }
      const temp = {}

      temp.type = item.dataset.src ? 'img' : item.dataset.text ? 'text' : 'view'
      if (temp.type === 'img') {
        temp.src = item.dataset.src
      }

      const bgCssString = item.background

      const backgroundImage = Util.parseImgBg(bgCssString)
      const backgroundColor = Util.parseBgColor(bgCssString)
      const linearGradient = Util.parseLinearGradient(bgCssString)

      const [top = 0, right = 0, bottom = 0, left = 0] = Util.parseBorder(item, scale)
      const border = [top, right, bottom, left]
      const borderRadius = Util.parseBorderRadius(item['border-radius'], scale)

      const fontSize = Number.parseInt(item['font-size'] || 0) * scale
      const lineH = item['line-height'] || 1.333
      const lineHeight = lineH === 'normal' ? fontSize : Number.parseFloat(lineH) * (lineH.includes('px') ? scale : fontSize)
      const letterSpacing = item['letter-spacing'] === 'normal' ? 0 : Number.parseFloat(item['letter-spacing'] || 0) * scale
      const fontWeight = item['font-weight'] !== '400'
      const textDecoration = item['text-decoration'].split(' ')[0]

      temp.rect = {
        x: item.left * scale - rootLeft,
        y: item.top * scale - rootTop,
        w: item.width * scale,
        h: item.height * scale,
        zIndex: item['z-index'] === 'auto' ? 0 : item['z-index'] * 1
      }

      temp.style = {
        backgroundColor,
        backgroundImage,
        linearGradient,
        borderRadius,
        border,
        color: item.color,
        fontSize,
        fontFamily: item['font-family'],
        fontWeight,
        textAlign: item['text-align'],
        textIndent: Number.parseFloat(item['text-indent'] || 0) * scale,
        textDecoration,
        lineHeight,
        letterSpacing
      }

      if (temp.type === 'text') {
        temp.content = item.dataset.text
        const [top = 0, right = 0, _bottom = 0, left = 0] = item.padding.split(' ').map(e => Number.parseInt(e || 0) * scale)
        temp.rect = {
          x: temp.rect.x + left,
          y: temp.rect.y + top,
          w: temp.rect.w - left + right,
          h: temp.rect.h,
          zIndex: temp.rect.zIndex
        }
        if (backgroundImage || backgroundColor) {
          temp.type = 'view'
          renderList.push(temp)

          const txtNode = Object.assign({}, { ...temp })
          txtNode.type = 'text'
          renderList.push(txtNode)
        }
        else {
          renderList.push(temp)
        }
      }
      else {
        renderList.push(temp)
      }

      if (i === 0) root = temp
    }

    return {
      root,
      renderList
    }
  }
}

export default class DrawPoster {
  constructor({ canvasThis, canvasId = 'canvasId', pageThis, renderClassName = 'poster', baseWidth = 750, onLayout, onRendered }) {
    this.onLayout = onLayout
    this.onRendered = onRendered

    this.canvasId = canvasId
    this.$canvasThis = canvasThis
    this.$pageThis = pageThis
    this.renderClassName = renderClassName
    this.root = {}

    this.context = uni.createCanvasContext(canvasId, canvasThis)
    const layout = new Layout(pageThis, this.renderClassName, baseWidth)
    layout.getElementTree(layoutTree => {
      this.root = layoutTree.root
      typeof this.onLayout === 'function' && this.onLayout(layoutTree)
      const renderList = layoutTree.renderList
      this.renderTree(renderList)
    })
  }

  get rootNode() {
    return this.root
  }

  clear() {
    const { rect: { w, h } } = this.root
    this.context.clearRect(0, 0, w, h)
  }

  async renderTree(renderList) {
    this.clear()
    // this.context.scale(0.5, 0.5)
    for (let i = 0; i < renderList.length; i++) {
      const ele = renderList[i]
      if (ele.type === 'view') {
        await this.drawView(ele)
      }
      else if (ele.type === 'img') {
        await this.drawImage(ele)
      }
      else if (ele.type === 'text') {
        await this.drawText(ele)
      }
    }
    typeof this.onRendered === 'function' && this.onRendered(renderList)
  }

  async drawView(ele = {}) {
    const { src, rect: { x, y, w, h }, style } = ele

    const {
      backgroundImage,
      backgroundColor,
      linearGradient,
      borderRadius,
      border
    } = style

    /* 有背景图绘制背景图 */
    if (backgroundImage) {
      const shallowEle = Object.assign({}, ele)
      shallowEle.src = backgroundImage
      await this.drawImage(shallowEle)
    }
    let gradient = ''
    if (linearGradient) {
      const { dir, colors } = linearGradient
      if (colors.length === 1) {
        this.context.fillStyle = colors[0]
      }
      else {
        // 1:从左到右;2:从上到下;3:左上角到右下角;4:右上角到左下角
        switch (dir) {
          case 'to left':
            gradient = this.context.createLinearGradient(x + h, y, x, y)
            break
          case 'to right':
            gradient = this.context.createLinearGradient(x, y, x + h, y)
            break
          case 'to top':
            gradient = this.context.createLinearGradient(x, y + h, x, y)
            break
          case 'to bottom':
            gradient = this.context.createLinearGradient(x, y, x + h, y)
            break
          default:
            gradient = this.context.createLinearGradient(x, y, x, y + h)
            break
        }

        if (gradient && colors.length) {
          for (let c = 0; c < colors.length; c++) {
            const color = colors[c].trim()
            if (colors.length < 2) {
              gradient.addColorStop(c, color)
            }
            else {
              const temp = c / (colors.length - 1)
              gradient.addColorStop(temp, color)
            }
          }
          this.context.fillStyle = gradient
        }
      }
    }
    else {
      this.context.fillStyle = backgroundColor || 'transparent'
    }

    this.context.save()
    await delayTime(10)
    this.setBorderRadius(x, y, w, h, borderRadius, border)
    this.context.fillRect(x, y, w, h)
    this.setBorderWidth(x, y, w, h, borderRadius, border)
    this.context.restore()
    await promiseDraw(this.context, true)
    await delayTime(5)
  }

  _drawBoxShadow(boxShadow, callback) {
    boxShadow = Util.transferBoxShadow(boxShadow)
    if (boxShadow) {
      this.context.setShadow(boxShadow.offsetX, boxShadow.offsetY, boxShadow.blur, boxShadow.color)
    }
    else {
      this.context.setShadow(0, 0, 0, '#ffffff')
    }

    callback && callback(boxShadow || {})
  }

  setRoundRectPath(x, y, w, h, borderRadius, border) {
    const [top, right, bottom, left] = border
    const [topLeft, topRight, rightBottom, leftBottom] = borderRadius
    const [tl, tr, br, bl] = borderRadius
    const setBorderSty = (border) => {
      const width = Math.round(border.width)
      if (border.style === 'dashed') this.context.setLineDash([width * 4, width * 4], 0)
      else this.context.setLineDash([])
      this.context.lineWidth = width

      this.context.strokeStyle = border.color
    }
    /* 四边相同设置 */
    if (top.width !== 0 && top.width === right.width && right.width === bottom.width && bottom.width === left
      .width) {
      setBorderSty(top)
      this.context.lineWidth = top.width * 2
      const radius = top.radius
      this.context.moveTo(x + topLeft, y)
      this.context.arcTo(x + w, y, x + w, y + h, topLeft)

      this.context.lineTo(x + w, y + h - topLeft)
      this.context.arcTo(x + w, y + h, x + w - topLeft, y + h, topLeft)

      this.context.lineTo(x + topLeft, y + h)
      this.context.arcTo(x, y + h, x, y + h - topLeft, topLeft)

      this.context.lineTo(x, y + topLeft)
      this.context.arcTo(x, y, x + topLeft, y, topLeft)
    }
    else {
      const lineWidth = top.width
      /* 不设置完整四边，不能设置radius，简化实现 */
      if (top.width) {
        this.context.beginPath()
        setBorderSty(top)
        this.context.moveTo(x, y)
        this.context.lineTo(x + w + lineWidth / 2, y)
        this.context.closePath()
        this.context.stroke()
      }
      if (right.width) {
        this.context.beginPath()
        setBorderSty(right)
        this.context.moveTo(x + w, y)
        this.context.lineTo(x + w, y + h + lineWidth / 2)
        this.context.closePath()
        this.context.stroke()
      }
      if (bottom.width) {
        this.context.beginPath()
        setBorderSty(bottom)
        this.context.moveTo(x + w, y + h)
        this.context.lineTo(x - lineWidth / 2, y + h)
        this.context.closePath()
        this.context.stroke()
      }
      if (left.width) {
        this.context.beginPath()
        setBorderSty(left)
        this.context.moveTo(x, y + h)
        this.context.lineTo(x, y - lineWidth)
        this.context.closePath()
        this.context.stroke()
      }
    }
  }

  setBorderRadius(x, y, w, h, borderRadius, border) {
    const [top, right, bottom, left] = border
    if (top.width !== 0 && top.width === right.width && right.width === bottom.width && bottom.width === left
      .width) {
      this.context.beginPath()
      this.setRoundRectPath(x, y, w, h, borderRadius, border)
      this.context.closePath()
      this.context.clip()
    }
  }

  setBorderWidth(x, y, w, h, borderRadius, border) {
    const [top, right, bottom, left] = border
    if (top.width || right.width || bottom.width || left.width) {
      this.context.beginPath()
      this.setRoundRectPath(x, y, w, h, borderRadius, border)
      this.context.closePath()
      this.context.stroke()
    }
  }

  async drawImage(ele = {}) {
    const { src, rect: { x, y, w, h }, style } = ele
    const { borderRadius, border } = style

    const res = await this.getImageInfo(src)
    if (!res) return
    // 图片加载完成后，再执行绘制操作
    const r = borderRadius[0]
    await delayTime(40)
    this.context.save()
    this.context.beginPath()
    // 绘制左上角圆弧
    this.context.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5)
    // 绘制border-top
    // 画一条线 x终点、y终点
    this.context.lineTo(x + w - r, y)
    // 绘制右上角圆弧
    this.context.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2)
    // 绘制border-right
    this.context.lineTo(x + w, y + h - r)
    // 绘制右下角圆弧
    this.context.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5)
    // 绘制左下角圆弧
    this.context.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI)
    // 绘制border-left
    this.context.lineTo(x, y + r)
    // 填充颜色(需要可以自行修改)
    this.context.setFillStyle('#ffffff')
    this.context.fill()
    // 剪切，剪切之后的绘画绘制剪切区域内进行，需要save与restore 这个很重要 不然没办法保存
    this.context.clip()

    this.context.drawImage(res, x, y, w, h)
    this.context.restore() // 恢复之前被切割的canvas，否则切割之外的就没办法用
    this.context.draw(true)
    await delayTime(70)
  }

  async drawText(ele = {}) {
    const { content, rect, style } = ele
    const text = content
    const { x, y, w, h } = rect
    const { fontSize, fontFamily, fontWeight, letterSpacing, color, textAlign, textIndent, lineHeight, textDecoration } = style

    this.context.setFillStyle(color)
    this.context.font = `${(fontWeight ? 'bold ' : '') + Math.round(Number.parseFloat(fontSize))}px ${fontFamily || 'Arial'}`
    this.context.setTextBaseline('normal')
    this.context.setTextAlign('left')
    // 首行缩进的宽度
    const textIndentWidth = textIndent / fontSize
    let tempText = text
    if (textIndentWidth) tempText = ' '.repeat(Math.round(textIndentWidth / 0.25)) + tempText
    const textLen = tempText.length
    const tempTextWordList = tempText.split('')

    let line = ''
    let lineIndex = 0 // 统计当前行
    const lines = []
    const baseH = fontSize + lineHeight / 2
    for (let i = 0; i < textLen; i++) {
      const word = tempTextWordList[i]
      line += word
      const testWidth = this.context.measureText(line).width
      if (testWidth > w) {
        lineIndex++
        lines.push({ x, y: y + baseH * lineIndex, w: testWidth, h: baseH, text: line })
        line = ''
      }
    }
    /* 不为空说明有最后一行 */
    if (line !== '') {
      lineIndex++
      const lastLineWidth = this.context.measureText(line).width
      let tempX = x
      const tempW = lastLineWidth
      if (textAlign === 'center') {
        tempX = x + (w - lastLineWidth) / 2
        // tempW = lastLineWidth
      }
      else if (textAlign === 'right') {
        tempX = x + (w - lastLineWidth)
        // tempW = lastLineWidth
      }
      else if (textAlign === 'left') {
        // left
        // tempW = lastLineWidth
      }
      lines.push({ x: tempX, y: y + Math.max(lines.length + 1, 1) * baseH, w: tempW, h: baseH, text: line })
    }
    for (let i = 0; i < lines.length; i++) {
      const row = lines[i]
      let tempX = row.x
      let tempW = row.w
      if (i === 0 && textIndentWidth) {
        tempX = tempX + textIndent
        tempW = tempW - textIndent
      }
      if (lineIndex * baseH > h + 2) {
        // let ellipsisW = this.context.measureText('...').width
        const lineText = `${row.text.substring(0, row.text.length - 2)}...`
        await this.context.fillText(lineText, row.x, row.y)
        break
      }
      else {
        await this.context.fillText(row.text, row.x, row.y)
      }
      this.setTextDecoration(textDecoration, color, tempX, row.y, tempW, baseH)
    }
    await promiseDraw(this.context, true)
  }

  drawLine(ele = {}) {
    const { src, rect: { x, y, w, h }, style: { lineType, color } } = ele

    this.context.setStrokeStyle(color)
    this.context.setLineWidth(w)
    this.context.setLineCap('round')
    if (lineType === 'dash') this.context.setLineDash([w * 5, w * 5], 0)
    else this.context.setLineDash([])
    this.context.beginPath()
    this.context.moveTo(x, y)
    this.context.lineTo(x + w, y + h)
    this.context.stroke()
    this.context.closePath()
  }

  setTextDecoration(textDecoration, color, x, y, w, lineHeight) {
    switch (textDecoration) {
      case 'line-through': {
        const midLine = Number.parseFloat(y) - lineHeight / 3
        this.context.setLineWidth(1)
        this.context.setStrokeStyle(color)
        this.context.moveTo(x, midLine)
        this.context.lineTo(x + w, midLine)
        this.context.stroke()
      }
        break
      case 'underline': {
        const midLine = Number.parseFloat(y) + 6
        this.context.setLineWidth(4)
        this.context.setStrokeStyle(color)
        this.context.moveTo(x, midLine)
        this.context.lineTo(x + w, midLine)
        this.context.stroke()
      }
        break
      default:
        // 左对齐
        break
    }
  }

  getImageInfo(src) {
    return new Promise(async (resolve) => {
      // #ifndef H5 || APP-PLUS
      if (/^data:image\/(\w+);base64/.test(src)) {
        src = await base64src(src)
      }
      // #endif
      uni.getImageInfo({
        src,
        success: (res) => {
          // 微信小程序会把相对路径转为不完整的绝对路径，要在前面加'/'
          // const res = await this.downloadImage(image.path)
          res.path = /^(http|\/\/|\/|wxfile|data:image\/(\w+);base64|file|bdfile)/.test(res.path) ? res.path : `/${res.path}`
          resolve(res.path)
        },
        fail(_err) {
          resolve(false)
        }
      })
    })
  }

  async getBase64Img(conf = {}) {
    // const pixelRatio = 2
    const { rect } = this.root

    const zoom = conf.zoom || 2

    const width = (conf.dw || rect.w)
    const height = (conf.dh || rect.h)

    const destWidth = (conf.dw || rect.w) * zoom
    const destHeight = (conf.dh || rect.h) * zoom
    const fileType = conf.fileType || 'png'

    await delayTime(300)
    return new Promise((resolve, reject) => {
      uni.canvasToTempFilePath({
        canvasId: this.canvasId,
        fileType,
        quality: conf.quality || 0.5,
        width,
        height,
        destWidth,
        destHeight,
        success: (res) => {
          resolve(res.tempFilePath)
        },
        fail: (err) => {
          console.log('生成图片失败:')
          reject(err)
        }
      }, this.$canvasThis)
    })
  }

  save(conf = {}) {
    const fileName = conf.fileName
    return new Promise((resolve, reject) => {
      this.getBase64Img(conf).then(tempFilePath => {
        if (!tempFilePath) return
        // #ifndef H5
        // 除了h5以外的其他端
        uni.saveImageToPhotosAlbum({
          filePath: tempFilePath,
          success(e) {
            resolve({ e, tempFilePath })
          },
          fail(err) {
            reject(err)
          }
        })
        // #endif
        // #ifdef H5
        const savePicture = (base64, name) => {
          const arr = base64.split(',')
          const bytes = atob(arr[1])
          const ab = new ArrayBuffer(bytes.length)
          const ia = new Uint8Array(ab)
          for (let i = 0; i < bytes.length; i++) {
            ia[i] = bytes.charCodeAt(i)
          }
          const blob = new Blob([ab], { type: 'application/octet-stream' })
          const url = URL.createObjectURL(blob)
          const a = document.createElement('a')
          a.href = url
          a.download = `${name || new Date().valueOf()}.png`
          const e = document.createEvent('MouseEvents')
          e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
          a.dispatchEvent(e)
          URL.revokeObjectURL(url)
        }
        resolve(savePicture(tempFilePath, fileName))
        // #endif
      })
    })
  }
}

function base64src(base64data) {
  return new Promise((resolve, reject) => {
    const fs = uni.getFileSystemManager()
    // 自定义文件名
    const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64data) || []
    if (!format) {
      reject(new Error('ERROR_BASE64SRC_PARSE'))
    }
    const time = new Date().getTime()
    const filePath = `${wx.env.USER_DATA_PATH}/${time}.${format}`
    const buffer = uni.base64ToArrayBuffer(bodyData)
    fs.writeFile({
      filePath,
      data: buffer,
      encoding: 'binary',
      success() {
        resolve(filePath)
      },
      fail(err) {
        reject(err)
        this.$emit('fail', {
          error: err
        })
        console.log('获取base64图片失败', err)
      }
    })
  })
}
